#include <stdio.h>  
#include <stdlib.h>  
#include <fcntl.h>  
#include <sys/mman.h>  
#include <unistd.h>  
#include <string.h>  

#define PHYS_BASE 0x80100000  	// FPGA在物理内存中的地址  
#define MAP_SIZE 4096			// 映射的大小，这里假设为4KB  

typedef struct fpga_pcie {
	void *mapped_base;
	int pcie_bar_fd;
} FPGA_PCIE_BAR_INFO;

FPGA_PCIE_BAR_INFO pcie_bar;

int fpga_pcie_bar_write(unsigned char *buffer, unsigned int data_size)
{
	void *virt_addr = NULL;
	
	if (NULL == buffer) {
		printf("buffer is empty\n");
		return -1;
	}
	
	if (data_size != MAP_SIZE) {
		printf("memcpy mmap size is 4096B\n");
		return -1;
	}
	
	// 指向映射区域的指针  
    virt_addr = pcie_bar.mapped_base;
	memcpy((unsigned int *)virt_addr, buffer, sizeof(data_size));
    //printf("FPGA BAR DATA = %#x\n", virt_addr);
	
	return 0;
}

int fpga_pcie_bar_read(unsigned char *buffer, unsigned int data_size)
{
	void *virt_addr = NULL;
	
	if (NULL == buffer) {
		printf("buffer is empty\n");
		return -1;
	}
	
	if (data_size != MAP_SIZE) {
		printf("memcpy mmap size is 4096B\n");
		return -1;
	}
	
	// 指向映射区域的指针  
    virt_addr = pcie_bar.mapped_base;
	memcpy(buffer, (unsigned int *)virt_addr, sizeof(data_size));
    //printf("FPGA BAR DATA = %#x\n", virt_addr);
	
	return 0;
}

int init_fpga_pcie_bar() {  
    int fd;  
    unsigned int temp = 0;
  
    // 打开/dev/mem设备文件  
    if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) {  
        perror("Can't open /dev/mem");  
        exit(EXIT_FAILURE);  
    }
	pcie_bar.pcie_bar_fd = fd;
	
    // 将物理地址映射到用户空间  
    pcie_bar.mapped_base = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PHYS_BASE);  
    if (pcie_bar.mapped_base == MAP_FAILED) {  
        perror("mmap() failed");  
        exit(EXIT_FAILURE);  
    }  
  
    // 这里你可以通过virt_addr来访问FPGA的内存。具体的读写操作取决于FPGA的协议。  
    // 例如，你可能需要写一些命令到FPGA的某个寄存器，然后读取响应。  
    // 这将涉及到对virt_addr的指针运算和内存访问。  
  
    // 假设我们向FPGA写入一个值  
    //unsigned int value = 0x12345678;  
    //*(unsigned int *)virt_addr = value;  
    
    return 0;  
}

void release_fpga_pcie_bar()
{
	// 清理：解除映射并关闭文件
    if (munmap(pcie_bar.mapped_base, MAP_SIZE) == -1) {  
        perror("munmap() failed");  
    }  
    close(pcie_bar.pcie_bar_fd);
}